<!DOCTYPE html><html><head><title>Sencha Documentation Project</title><link rel="stylesheet" href="../reset.css" type="text/css"><link rel="stylesheet" href="../prettify.css" type="text/css"><link rel="stylesheet" href="../prettify_sa.css" type="text/css"><script type="text/javascript" src="../prettify.js"></script></head><body onload="prettyPrint()"><pre class="prettyprint"><pre><span id='Ext-util.Observable'>/**
</span> * @class Ext.util.Observable
 * Base class that provides a common interface for publishing events. Subclasses are expected to
 * to have a property &quot;events&quot; with all the events defined, and, optionally, a property &quot;listeners&quot;
 * with configured listeners defined.&lt;br&gt;
 * For example:
 * &lt;pre&gt;&lt;code&gt;
Employee = Ext.extend(Ext.util.Observable, {
    constructor: function(config){
        this.name = config.name;
        this.addEvents({
            &quot;fired&quot; : true,
            &quot;quit&quot; : true
        });

        // Copy configured listeners into *this* object so that the base class&amp;#39;s
        // constructor will add them.
        this.listeners = config.listeners;

        // Call our superclass constructor to complete construction process.
        Employee.superclass.constructor.call(this, config)
    }
});
&lt;/code&gt;&lt;/pre&gt;
 * This could then be used like this:&lt;pre&gt;&lt;code&gt;
var newEmployee = new Employee({
    name: employeeName,
    listeners: {
        quit: function() {
            // By default, &quot;this&quot; will be the object that fired the event.
            alert(this.name + &quot; has quit!&quot;);
        }
    }
});
&lt;/code&gt;&lt;/pre&gt;
 */

Ext.define('Ext.util.Observable', {

    /* Begin Definitions */

    requires: ['Ext.util.Event'],

    statics: {
<span id='Ext-util.Observable-method-releaseCapture'>        /**
</span>         * Removes &lt;b&gt;all&lt;/b&gt; added captures from the Observable.
         * @param {Observable} o The Observable to release
         * @static
         */
        releaseCapture: function(o) {
            o.fireEvent = this.prototype.fireEvent;
        },

<span id='Ext-util.Observable-method-capture'>        /**
</span>         * Starts capture on the specified Observable. All events will be passed
         * to the supplied function with the event name + standard signature of the event
         * &lt;b&gt;before&lt;/b&gt; the event is fired. If the supplied function returns false,
         * the event will not fire.
         * @param {Observable} o The Observable to capture events from.
         * @param {Function} fn The function to call when an event is fired.
         * @param {Object} scope (optional) The scope (&lt;code&gt;this&lt;/code&gt; reference) in which the function is executed. Defaults to the Observable firing the event.
         * @static
         */
        capture: function(o, fn, scope) {
            o.fireEvent = Ext.Function.createInterceptor(o.fireEvent, fn, scope);
        },

<span id='Ext-util.Observable-method-observe'>        /**
</span>Sets observability on the passed class constructor.

This makes any event fired on any instance of the passed class also fire a single event through
the __class__ allowing for central handling of events on many instances at once.

Usage:

    Ext.util.Observable.observe(Ext.data.Connection);
    Ext.data.Connection.on('beforerequest', function(con, options) {
        console.log('Ajax request made to ' + options.url);
    });

         * @param {Function} c The class constructor to make observable.
         * @param {Object} listeners An object containing a series of listeners to add. See {@link #addListener}.
         * @static
         * @markdown
         */
        observe: function(cls, listeners) {
            if (cls) {
                if (!cls.isObservable) {
                    Ext.applyIf(cls, new this());
                    this.capture(cls.prototype, cls.fireEvent, cls);
                }
                if (Ext.isObject(listeners)) {
                    cls.on(listeners);
                }
                return cls;
            }
        }
    },

    /* End Definitions */

<span id='Ext-util.Observable-cfg-listeners'>    /**
</span>    * @cfg {Object} listeners (optional) &lt;p&gt;A config object containing one or more event handlers to be added to this
    * object during initialization.  This should be a valid listeners config object as specified in the
    * {@link #addListener} example for attaching multiple handlers at once.&lt;/p&gt;
    * &lt;br&gt;&lt;p&gt;&lt;b&gt;&lt;u&gt;DOM events from ExtJs {@link Ext.Component Components}&lt;/u&gt;&lt;/b&gt;&lt;/p&gt;
    * &lt;br&gt;&lt;p&gt;While &lt;i&gt;some&lt;/i&gt; ExtJs Component classes export selected DOM events (e.g. &quot;click&quot;, &quot;mouseover&quot; etc), this
    * is usually only done when extra value can be added. For example the {@link Ext.view.View DataView}'s
    * &lt;b&gt;&lt;code&gt;{@link Ext.view.View#click click}&lt;/code&gt;&lt;/b&gt; event passing the node clicked on. To access DOM
    * events directly from a child element of a Component, we need to specify the &lt;code&gt;element&lt;/code&gt; option to
    * identify the Component property to add a DOM listener to:
    * &lt;pre&gt;&lt;code&gt;
new Ext.panel.Panel({
    width: 400,
    height: 200,
    dockedItems: [{
        xtype: 'toolbar'
    }],
    listeners: {
        click: {
            element: 'el', //bind to the underlying el property on the panel
            fn: function(){ console.log('click el'); }
        },
        dblclick: {
            element: 'body', //bind to the underlying body property on the panel
            fn: function(){ console.log('dblclick body'); }
        }
    }
});
&lt;/code&gt;&lt;/pre&gt;
    * &lt;/p&gt;
    */
    // @private
    isObservable: true,

    constructor: function(config) {
        var me = this;

        Ext.apply(me, config);
        if (me.listeners) {
            me.on(me.listeners);
            delete me.listeners;
        }
        me.events = me.events || {};

        if (me.bubbleEvents) {
            me.enableBubble(me.bubbleEvents);
        }
    },

    // @private
    eventOptionsRe : /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate|element|vertical|horizontal)$/,

<span id='Ext-util.Observable-method-addManagedListener'>    /**
</span>     * &lt;p&gt;Adds listeners to any Observable object (or Element) which are automatically removed when this Component
     * is destroyed.
     * @param {Observable/Element} item The item to which to add a listener/listeners.
     * @param {Object/String} ename The event name, or an object containing event name properties.
     * @param {Function} fn Optional. If the &lt;code&gt;ename&lt;/code&gt; parameter was an event name, this
     * is the handler function.
     * @param {Object} scope Optional. If the &lt;code&gt;ename&lt;/code&gt; parameter was an event name, this
     * is the scope (&lt;code&gt;this&lt;/code&gt; reference) in which the handler function is executed.
     * @param {Object} opt Optional. If the &lt;code&gt;ename&lt;/code&gt; parameter was an event name, this
     * is the {@link Ext.util.Observable#addListener addListener} options.
     */
    addManagedListener : function(item, ename, fn, scope, options) {
        var me = this,
            managedListeners = me.managedListeners = me.managedListeners || [],
            config;

        if (Ext.isObject(ename)) {
            options = ename;
            for (ename in options) {
                if (options.hasOwnProperty(ename)) {
                    config = options[ename];
                    if (!me.eventOptionsRe.test(ename)) {
                        me.addManagedListener(item, ename, config.fn || config, config.scope || options.scope, config.fn ? config : options);
                    }
                }
            }
        }
        else {
            managedListeners.push({
                item: item,
                ename: ename,
                fn: fn,
                scope: scope,
                options: options
            });

            item.on(ename, fn, scope, options);
        }
    },

<span id='Ext-util.Observable-method-removeManagedListener'>    /**
</span>     * Removes listeners that were added by the {@link #mon} method.
     * @param {Observable|Element} item The item from which to remove a listener/listeners.
     * @param {Object|String} ename The event name, or an object containing event name properties.
     * @param {Function} fn Optional. If the &lt;code&gt;ename&lt;/code&gt; parameter was an event name, this
     * is the handler function.
     * @param {Object} scope Optional. If the &lt;code&gt;ename&lt;/code&gt; parameter was an event name, this
     * is the scope (&lt;code&gt;this&lt;/code&gt; reference) in which the handler function is executed.
     */
     removeManagedListener : function(item, ename, fn, scope) {
        var me = this,
            options,
            config,
            managedListeners,
            managedListener,
            length,
            i;

        if (Ext.isObject(ename)) {
            options = ename;
            for (ename in options) {
                if (options.hasOwnProperty(ename)) {
                    config = options[ename];
                    if (!me.eventOptionsRe.test(ename)) {
                        me.removeManagedListener(item, ename, config.fn || config, config.scope || options.scope);
                    }
                }
            }
        }

        managedListeners = me.managedListeners ? me.managedListeners.slice() : [];
        length = managedListeners.length;

        for (i = 0; i &lt; length; i++) {
            managedListener = managedListeners[i];
            if (managedListener.item === item &amp;&amp; managedListener.ename === ename &amp;&amp; (!fn || managedListener.fn === fn) &amp;&amp; (!scope || managedListener.scope === scope)) {
                Ext.Array.remove(me.managedListeners, managedListener);
                item.un(managedListener.ename, managedListener.fn, managedListener.scope);
            }
        }
    },

<span id='Ext-util.Observable-method-fireEvent'>    /**
</span>     * &lt;p&gt;Fires the specified event with the passed parameters (minus the event name).&lt;/p&gt;
     * &lt;p&gt;An event may be set to bubble up an Observable parent hierarchy (See {@link Ext.Component#getBubbleTarget})
     * by calling {@link #enableBubble}.&lt;/p&gt;
     * @param {String} eventName The name of the event to fire.
     * @param {Object...} args Variable number of parameters are passed to handlers.
     * @return {Boolean} returns false if any of the handlers return false otherwise it returns true.
     */
    fireEvent: function() {
        var me = this,
            args = Ext.Array.toArray(arguments),
            ename = args[0].toLowerCase(),
            ret = true,
            event = me.events[ename],
            queue = me.eventQueue,
            parent;

        if (me.eventsSuspended === true) {
            if (queue) {
                queue.push(args);
            }
        } else if (event &amp;&amp; Ext.isObject(event) &amp;&amp; event.bubble) {
            if (event.fire.apply(event, args.slice(1)) === false) {
                return false;
            }
            parent = me.getBubbleTarget &amp;&amp; me.getBubbleTarget();
            if (parent &amp;&amp; parent.isObservable) {
                if (!parent.events[ename] || !Ext.isObject(parent.events[ename]) || !parent.events[ename].bubble) {
                    parent.enableBubble(ename);
                }
                return parent.fireEvent.apply(parent, args);
            }
        } else if (event &amp;&amp; Ext.isObject(event)) {
            args.shift();
            ret = event.fire.apply(event, args);
        }
        return ret;
    },

<span id='Ext-util.Observable-method-addListener'>    /**
</span>     * Appends an event handler to this object.
     * @param {String}   eventName The name of the event to listen for. May also be an object who's property names are event names. See
     * @param {Function} handler The method the event invokes.
     * @param {Object}   scope (optional) The scope (&lt;code&gt;&lt;b&gt;this&lt;/b&gt;&lt;/code&gt; reference) in which the handler function is executed.
     * &lt;b&gt;If omitted, defaults to the object which fired the event.&lt;/b&gt;
     * @param {Object}   options (optional) An object containing handler configuration.
     * properties. This may contain any of the following properties:&lt;ul&gt;
     * &lt;li&gt;&lt;b&gt;scope&lt;/b&gt; : Object&lt;div class=&quot;sub-desc&quot;&gt;The scope (&lt;code&gt;&lt;b&gt;this&lt;/b&gt;&lt;/code&gt; reference) in which the handler function is executed.
     * &lt;b&gt;If omitted, defaults to the object which fired the event.&lt;/b&gt;&lt;/div&gt;&lt;/li&gt;
     * &lt;li&gt;&lt;b&gt;delay&lt;/b&gt; : Number&lt;div class=&quot;sub-desc&quot;&gt;The number of milliseconds to delay the invocation of the handler after the event fires.&lt;/div&gt;&lt;/li&gt;
     * &lt;li&gt;&lt;b&gt;single&lt;/b&gt; : Boolean&lt;div class=&quot;sub-desc&quot;&gt;True to add a handler to handle just the next firing of the event, and then remove itself.&lt;/div&gt;&lt;/li&gt;
     * &lt;li&gt;&lt;b&gt;buffer&lt;/b&gt; : Number&lt;div class=&quot;sub-desc&quot;&gt;Causes the handler to be scheduled to run in an {@link Ext.util.DelayedTask} delayed
     * by the specified number of milliseconds. If the event fires again within that time, the original
     * handler is &lt;em&gt;not&lt;/em&gt; invoked, but the new handler is scheduled in its place.&lt;/div&gt;&lt;/li&gt;
     * &lt;li&gt;&lt;b&gt;target&lt;/b&gt; : Observable&lt;div class=&quot;sub-desc&quot;&gt;Only call the handler if the event was fired on the target Observable, &lt;i&gt;not&lt;/i&gt;
     * if the event was bubbled up from a child Observable.&lt;/div&gt;&lt;/li&gt;
     * &lt;li&gt;&lt;b&gt;element&lt;/b&gt; : String&lt;div class=&quot;sub-desc&quot;&gt;&lt;b&gt;This option is only valid for listeners bound to {@link Ext.Component Components}.&lt;/b&gt;
     * The name of a Component property which references an element to add a listener to.
     * &lt;p&gt;This option is useful during Component construction to add DOM event listeners to elements of {@link Ext.Component Components} which
     * will exist only after the Component is rendered. For example, to add a click listener to a Panel's body:&lt;pre&gt;&lt;code&gt;
new Ext.panel.Panel({
    title: 'The title',
    listeners: {
        click: this.handlePanelClick,
        element: 'body'
    }
});
&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
     * &lt;p&gt;When added in this way, the options available are the options applicable to {@link Ext.core.Element#addListener}&lt;/p&gt;&lt;/div&gt;&lt;/li&gt;
     * &lt;/ul&gt;&lt;br&gt;
     * &lt;p&gt;
     * &lt;b&gt;Combining Options&lt;/b&gt;&lt;br&gt;
     * Using the options argument, it is possible to combine different types of listeners:&lt;br&gt;
     * &lt;br&gt;
     * A delayed, one-time listener.
     * &lt;pre&gt;&lt;code&gt;
myPanel.on('hide', this.handleClick, this, {
single: true,
delay: 100
});&lt;/code&gt;&lt;/pre&gt;
     * &lt;p&gt;
     * &lt;b&gt;Attaching multiple handlers in 1 call&lt;/b&gt;&lt;br&gt;
     * The method also allows for a single argument to be passed which is a config object containing properties
     * which specify multiple events. For example:&lt;pre&gt;&lt;code&gt;
myGridPanel.on({
    cellClick: this.onCellClick,
    mouseover: this.onMouseOver,
    mouseout: this.onMouseOut,
    scope: this // Important. Ensure &quot;this&quot; is correct during handler execution
});
&lt;/code&gt;&lt;/pre&gt;.
     * &lt;p&gt;
     */
    addListener: function(ename, fn, scope, options) {
        var me = this,
            config,
            event;

        if (Ext.isObject(ename)) {
            options = ename;
            for (ename in options) {
                if (options.hasOwnProperty(ename)) {
                    config = options[ename];
                    if (!me.eventOptionsRe.test(ename)) {
                        me.addListener(ename, config.fn || config, config.scope || options.scope, config.fn ? config : options);
                    }
                }
            }
        }
        else {
            ename = ename.toLowerCase();
            me.events[ename] = me.events[ename] || true;
            event = me.events[ename] || true;
            if (Ext.isBoolean(event)) {
                me.events[ename] = event = new Ext.util.Event(me, ename);
            }
            event.addListener(fn, scope, Ext.isObject(options) ? options : {});
        }
    },

<span id='Ext-util.Observable-method-removeListener'>    /**
</span>     * Removes an event handler.
     * @param {String}   eventName The type of event the handler was associated with.
     * @param {Function} handler   The handler to remove. &lt;b&gt;This must be a reference to the function passed into the {@link #addListener} call.&lt;/b&gt;
     * @param {Object}   scope     (optional) The scope originally specified for the handler.
     */
    removeListener: function(ename, fn, scope) {
        var me = this,
            config,
            event,
            options;

        if (Ext.isObject(ename)) {
            options = ename;
            for (ename in options) {
                if (options.hasOwnProperty(ename)) {
                    config = options[ename];
                    if (!me.eventOptionsRe.test(ename)) {
                        me.removeListener(ename, config.fn || config, config.scope || options.scope);
                    }
                }
            }
        } else {
            ename = ename.toLowerCase();
            event = me.events[ename];
            if (event.isEvent) {
                event.removeListener(fn, scope);
            }
        }
    },

<span id='Ext-util.Observable-method-clearListeners'>    /**
</span>     * Removes all listeners for this object including the managed listeners
     */
    clearListeners: function() {
        var events = this.events,
            event,
            key;

        for (key in events) {
            if (events.hasOwnProperty(key)) {
                event = events[key];
                if (event.isEvent) {
                    event.clearListeners();
                }
            }
        }

        this.clearManagedListeners();
    },

    //&lt;debug&gt;
    purgeListeners : function() {
        console.warn('Observable: purgeListeners has been deprecated. Please use clearListeners.');
        return this.clearListeners.apply(this, arguments);
    },
    //&lt;/debug&gt;

<span id='Ext-util.Observable-method-clearManagedListeners'>    /**
</span>     * Removes all managed listeners for this object.
     */
    clearManagedListeners : function() {
        var managedListeners = this.managedListeners || [],
            i = 0,
            len = managedListeners.length,
            managedListener;

        for (; i &lt; len; i++) {
            managedListener = managedListeners[i];
            managedListener.item.un(managedListener.ename, managedListener.fn, managedListener.scope);
        }

        this.managedListeners = [];
    },

    //&lt;debug&gt;
    purgeManagedListeners : function() {
        console.warn('Observable: purgeManagedListeners has been deprecated. Please use clearManagedListeners.');
        return this.clearManagedListeners.apply(this, arguments);
    },
    //&lt;/debug&gt;

<span id='Ext-util.Observable-method-addEvents'>    /**
</span>     * Adds the specified events to the list of events which this Observable may fire.
     * @param {Object/String} o Either an object with event names as properties with a value of &lt;code&gt;true&lt;/code&gt;
     * or the first event name string if multiple event names are being passed as separate parameters.
     * @param {String} [additional] Optional additional event names if multiple event names are being passed as separate parameters.
     * Usage:&lt;pre&gt;&lt;code&gt;
this.addEvents('storeloaded', 'storecleared');
&lt;/code&gt;&lt;/pre&gt;
     */
    addEvents: function(o) {
        var me = this,
            args,
            len,
            i;
            
            me.events = me.events || {};
        if (Ext.isString(o)) {
            args = arguments;
            i = args.length;
            
            while (i--) {
                me.events[args[i]] = me.events[args[i]] || true;
            }
        } else {
            Ext.applyIf(me.events, o);
        }
    },

<span id='Ext-util.Observable-method-hasListener'>    /**
</span>     * Checks to see if this object has any listeners for a specified event
     * @param {String} eventName The name of the event to check for
     * @return {Boolean} True if the event is being listened for, else false
     */
    hasListener: function(ename) {
        var event = this.events[ename.toLowerCase()];
        return event &amp;&amp; event.isEvent === true &amp;&amp; event.listeners.length &gt; 0;
    },

<span id='Ext-util.Observable-method-suspendEvents'>    /**
</span>     * Suspend the firing of all events. (see {@link #resumeEvents})
     * @param {Boolean} queueSuspended Pass as true to queue up suspended events to be fired
     * after the {@link #resumeEvents} call instead of discarding all suspended events;
     */
    suspendEvents: function(queueSuspended) {
        this.eventsSuspended = true;
        if (queueSuspended &amp;&amp; !this.eventQueue) {
            this.eventQueue = [];
        }
    },

<span id='Ext-util.Observable-method-resumeEvents'>    /**
</span>     * Resume firing events. (see {@link #suspendEvents})
     * If events were suspended using the &lt;code&gt;&lt;b&gt;queueSuspended&lt;/b&gt;&lt;/code&gt; parameter, then all
     * events fired during event suspension will be sent to any listeners now.
     */
    resumeEvents: function() {
        var me = this,
            queued = me.eventQueue || [];

        me.eventsSuspended = false;
        delete me.eventQueue;

        Ext.each(queued,
        function(e) {
            me.fireEvent.apply(me, e);
        });
    },

<span id='Ext-util.Observable-method-relayEvents'>    /**
</span>     * Relays selected events from the specified Observable as if the events were fired by &lt;code&gt;&lt;b&gt;this&lt;/b&gt;&lt;/code&gt;.
     * @param {Object} origin The Observable whose events this object is to relay.
     * @param {Array} events Array of event names to relay.
     */
    relayEvents : function(origin, events, prefix) {
        prefix = prefix || '';
        var me = this,
            len = events.length,
            i = 0,
            oldName,
            newName;

        for (; i &lt; len; i++) {
            oldName = events[i].substr(prefix.length);
            newName = prefix + oldName;
            me.events[newName] = me.events[newName] || true;
            origin.on(oldName, me.createRelayer(newName));
        }
    },

<span id='Ext-util.Observable-method-createRelayer'>    /**
</span>     * @private
     * Creates an event handling function which refires the event from this object as the passed event name.
     * @param newName
     * @returns {Function}
     */
    createRelayer: function(newName){
        var me = this;
        return function(){
            return me.fireEvent.apply(me, [newName].concat(Array.prototype.slice.call(arguments, 0, -1)));
        };
    },

<span id='Ext-util.Observable-method-enableBubble'>    /**
</span>     * &lt;p&gt;Enables events fired by this Observable to bubble up an owner hierarchy by calling
     * &lt;code&gt;this.getBubbleTarget()&lt;/code&gt; if present. There is no implementation in the Observable base class.&lt;/p&gt;
     * &lt;p&gt;This is commonly used by Ext.Components to bubble events to owner Containers. See {@link Ext.Component#getBubbleTarget}. The default
     * implementation in Ext.Component returns the Component's immediate owner. But if a known target is required, this can be overridden to
     * access the required target more quickly.&lt;/p&gt;
     * &lt;p&gt;Example:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;
Ext.override(Ext.form.field.Base, {
//  Add functionality to Field&amp;#39;s initComponent to enable the change event to bubble
initComponent : Ext.Function.createSequence(Ext.form.field.Base.prototype.initComponent, function() {
    this.enableBubble('change');
}),

//  We know that we want Field&amp;#39;s events to bubble directly to the FormPanel.
getBubbleTarget : function() {
    if (!this.formPanel) {
        this.formPanel = this.findParentByType('form');
    }
    return this.formPanel;
}
});

var myForm = new Ext.formPanel({
title: 'User Details',
items: [{
    ...
}],
listeners: {
    change: function() {
        // Title goes red if form has been modified.
        myForm.header.setStyle('color', 'red');
    }
}
});
&lt;/code&gt;&lt;/pre&gt;
     * @param {String/Array} events The event name to bubble, or an Array of event names.
     */
    enableBubble: function(events) {
        var me = this;
        if (!Ext.isEmpty(events)) {
            events = Ext.isArray(events) ? events: Ext.Array.toArray(arguments);
            Ext.each(events,
            function(ename) {
                ename = ename.toLowerCase();
                var ce = me.events[ename] || true;
                if (Ext.isBoolean(ce)) {
                    ce = new Ext.util.Event(me, ename);
                    me.events[ename] = ce;
                }
                ce.bubble = true;
            });
        }
    }
}, function() {
<span id='Ext-util.Observable-method-un'>    /**
</span>     * Removes an event handler (shorthand for {@link #removeListener}.)
     * @param {String}   eventName     The type of event the handler was associated with.
     * @param {Function} handler       The handler to remove. &lt;b&gt;This must be a reference to the function passed into the {@link #addListener} call.&lt;/b&gt;
     * @param {Object}   scope         (optional) The scope originally specified for the handler.
     * @method un
     */

<span id='Ext-util.Observable-method-on'>    /**
</span>     * Appends an event handler to this object (shorthand for {@link #addListener}.)
     * @param {String}   eventName     The type of event to listen for
     * @param {Function} handler       The method the event invokes
     * @param {Object}   scope         (optional) The scope (&lt;code&gt;&lt;b&gt;this&lt;/b&gt;&lt;/code&gt; reference) in which the handler function is executed.
     * &lt;b&gt;If omitted, defaults to the object which fired the event.&lt;/b&gt;
     * @param {Object}   options       (optional) An object containing handler configuration.
     * @method on
     */

    this.createAlias({
        on: 'addListener',
        un: 'removeListener',
        mon: 'addManagedListener',
        mun: 'removeManagedListener'
    });

    //deprecated, will be removed in 5.0
    this.observeClass = this.observe;

    Ext.apply(Ext.util.Observable.prototype, function(){
        // this is considered experimental (along with beforeMethod, afterMethod, removeMethodListener?)
        // allows for easier interceptor and sequences, including cancelling and overwriting the return value of the call
        // private
        function getMethodEvent(method){
            var e = (this.methodEvents = this.methodEvents || {})[method],
                returnValue,
                v,
                cancel,
                obj = this;

            if (!e) {
                this.methodEvents[method] = e = {};
                e.originalFn = this[method];
                e.methodName = method;
                e.before = [];
                e.after = [];

                var makeCall = function(fn, scope, args){
                    if((v = fn.apply(scope || obj, args)) !== undefined){
                        if (typeof v == 'object') {
                            if(v.returnValue !== undefined){
                                returnValue = v.returnValue;
                            }else{
                                returnValue = v;
                            }
                            cancel = !!v.cancel;
                        }
                        else
                            if (v === false) {
                                cancel = true;
                            }
                            else {
                                returnValue = v;
                            }
                    }
                };

                this[method] = function(){
                    var args = Array.prototype.slice.call(arguments, 0),
                        b, i, len;
                    returnValue = v = undefined;
                    cancel = false;

                    for(i = 0, len = e.before.length; i &lt; len; i++){
                        b = e.before[i];
                        makeCall(b.fn, b.scope, args);
                        if (cancel) {
                            return returnValue;
                        }
                    }

                    if((v = e.originalFn.apply(obj, args)) !== undefined){
                        returnValue = v;
                    }

                    for(i = 0, len = e.after.length; i &lt; len; i++){
                        b = e.after[i];
                        makeCall(b.fn, b.scope, args);
                        if (cancel) {
                            return returnValue;
                        }
                    }
                    return returnValue;
                };
            }
            return e;
        }

        return {
            // these are considered experimental
            // allows for easier interceptor and sequences, including cancelling and overwriting the return value of the call
            // adds an 'interceptor' called before the original method
            beforeMethod : function(method, fn, scope){
                getMethodEvent.call(this, method).before.push({
                    fn: fn,
                    scope: scope
                });
            },

            // adds a 'sequence' called after the original method
            afterMethod : function(method, fn, scope){
                getMethodEvent.call(this, method).after.push({
                    fn: fn,
                    scope: scope
                });
            },

            removeMethodListener: function(method, fn, scope){
                var e = this.getMethodEvent(method),
                    i, len;
                for(i = 0, len = e.before.length; i &lt; len; i++){
                    if(e.before[i].fn == fn &amp;&amp; e.before[i].scope == scope){
                        e.before.splice(i, 1);
                        return;
                    }
                }
                for(i = 0, len = e.after.length; i &lt; len; i++){
                    if(e.after[i].fn == fn &amp;&amp; e.after[i].scope == scope){
                        e.after.splice(i, 1);
                        return;
                    }
                }
            },

            toggleEventLogging: function(toggle) {
                Ext.util.Observable[toggle ? 'capture' : 'releaseCapture'](this, function(en) {
                    if (Ext.isDefined(Ext.global.console)) {
                        Ext.global.console.log(en, arguments);
                    }
                });
            }
        };
    }());
});
</pre></pre></body></html>